package com.example.threadcoroutine

import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.widget.Button
import android.widget.TextView
import java.lang.Exception
import java.util.Objects

/**
 * 线程 Thread
 * 协程 Coroutine
 * Room
 *
 * 进程  ：正在运行的程序 （不负责任务处理，负责程序运行所需的资源-内存资源）
 * 线程  ：执行任务的最小单位 （真正处理任务）
 * 多线程：多个线程去完成一个功能
 *
 * Java
 * Thread
 * Runnable
 * Handler
 * AsyncTask
 * Pool
 *
 * Activity的启动 onCreate onStart onRestart onResume 这几个方法会影响app的启动速度
 * 这里不要做耗时操作，如果非要做 两种解决办法：
 *      1. 用一个线程去处理
 *      2. 给app加一个启动页面
 *
 * android 线程分为两类
 *     UI主线程：
 *              负责UI的相关事务 添加控件 显示控件 改变控件内容 用户交互
 *              和UI相关的事情必须放在UI主线程处理
 *              ANR（application not responding) 程序无响应
 *              运行 ->  UI线程(和用户交互) -> 加载数据10m(阻塞主线程) -> 继续执行
 *              Only the original thread that created a view hierarchy can touch its views
 *     子线程
 *              处理耗时的任务（加载图片资源 视频 音频   写入文件  网络加载 数据加载 ）
 *              如何开启一个线程  Thread
 *              -Thread.currentThread() 获取当前线程
 *              - name 设置线程名称
 *              - start() 启动线程
 *
 *                  a： 定义一个类继承于Thread类
 *                  b:    定义一个类实现Runnable接口
 *
 *
 *    Handler 子线程和主线程之间交互
 *          -handler 管理消息的分发
 *                  -handleMessage()  线程处理消息
 *          -Message 携带的数据
 *                  - what 可以通过这个属性确定哪个线程发送过来的(自己约定）
 *                  -obj 具体携带的数据
 *          -MessageQueue 存储消息
 *          -Looper  从消息队列获取消息
 *                  - dispatchMessage -> handler
 *
 *          -sendEmptyMessage(what) 发送空消息 不带数据
 *          -sendMessage(msg)
 *          -sendMessageDelayed(msg,1000)延迟发送
 *
 *  Thread 和 Runnable的关系
 *  Thread开启一个线程
 *  Runnable 线程执行的具体任务
 *
 *  线程的执行时间和顺序是不定的，靠CPU资源分配
 *  线程的状态
 *      - 启动状态   start()
 *      - 就绪状态  （随时等待cpu）
 *      -  运行状态  （执行任务）
 *      -  阻塞状态   （没有时间片 被强行暂停）
 *      -  销毁状态    （执行完毕）
 *
 * 多个线程操作同一个资源时 考虑是否需要加锁
 * 同步代码块 synchronized()
 * 每一个对象都有一个锁 :加锁时必须确保操作的是同一个(对象)锁
 */
class MainActivity : AppCompatActivity() {
    lateinit var mTextView:TextView
    lateinit var thread1:Thread
    lateinit var thread2:Thread

    var ticket = 50
    val obj = String()
    //创建Handler对象
    val mHandler = object : Handler(Looper.getMainLooper()){
        override fun handleMessage(msg: Message) {
            //处理消息
            when(msg.what){
                1 ->{
                    mTextView.text = msg.obj as String
                }
                2 ->{
                    thread2.interrupt()
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mTextView = findViewById<TextView>(R.id.textView)
        val mBtn = findViewById<Button>(R.id.button)

        mBtn.setOnClickListener {
            //启动线程
            /*MyThread().apply {
                name = "子线程1"
                start()
            }*/

//            thread1 = Thread(MyRunnable1(), "计数器线程")
//            thread2 = Thread(MyRunnable2(), "秒表线程")
//            thread1.start()
//            thread2.start()

            /*
            Thread(object : Runnable{
                override fun run() {
                    for (i in 1..50) {
                        Log.v("pxd", "${Thread.currentThread().name}: $i")
                        Thread.sleep(200)
                    }
                }
            }, "计数器线程")
            */

            //抢票
//            val task = MyRunnable1()
//            Thread(task, "重庆").start()
//            Thread(task, "成都").start()
//            Thread(task, "上海").start()
        }
    }

    inner class MyRunnable1: Runnable{
        override fun run() {
            while (true) {
                synchronized(obj) {
                    if (ticket > 0) {
                        //买票
                        Log.v("pxd", "${Thread.currentThread().name} 出票：$ticket")
                        ticket--
                    }
                }
                if (ticket == 0) break
            }
        }
    }

    class MyRunnable2: Runnable{
        override fun run() {
            for (i in 1..20) {
                Log.v("pxd", "${Thread.currentThread().name}: $i")
                try {
                    Thread.sleep(200)
                }catch (e:Exception){
                    e.printStackTrace()
                }
            }
        }
    }

    inner class  MyThread: Thread(){
        override fun run() {
            for (i in 5 downTo 1){
                //通知主线程显示数据
                val msg = Message()
                msg.what = 1
                msg.obj = "$i"
                mHandler.sendMessageDelayed(msg,1000)
                //睡一秒钟
                Thread.sleep(1000)
            }
        }
    }
}



/**
A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority.
Each thread may or may not also be marked as a daemon.守护线程  A  B(daemon)
When code running in some thread creates a new Thread object,
the new thread has its priority initially set equal to the priority of the creating thread,
and is a daemon thread if and only if the creating thread is a daemon.
When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:
The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

There are two ways to create a new thread of execution.
One is to declare a class to be a subclass of Thread.
This subclass should override the run method of class Thread.
An instance of the subclass can then be allocated and started.
For example, a thread that computes primes larger than a stated value could be written as follows:

class PrimeThread extends Thread {
    long minPrime;
    PrimeThread(long minPrime) {
        this.minPrime = minPrime;
   }

    public void run() {
    // compute primes larger than minPrime
     . . .
    }
}


The following code would then create a thread and start it running:
PrimeThread p = new PrimeThread(143);
p.start();

The other way to create a thread is to declare a class that implements the Runnable interface.
That class then implements the run method. An instance of the class can then be allocated, passed as an argument when creating Thread, and started. The same example in this other style looks like the following:

class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}

public void run() {
// compute primes larger than minPrime
 . . .
}
}


The following code would then create a thread and start it running:
PrimeRun p = new PrimeRun(143);
new Thread(p).start();

Every thread has a name for identification purposes. More than one thread may have the same name. If a name is not specified when a thread is created, a new name is generated for it.
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
 */










